//
//  RGBManager.m
//  蓝牙
//
//  Created by 赵鹏宇 on 16/2/16.
//  Copyright © 2016年 赵鹏宇. All rights reserved.
//
#import "RGBManager.h"
#import "mo_audio.h" //stuff that helps set up low-level audio
#import "FFTHelper.h"
#import <AVFoundation/AVFoundation.h>
#import "BluetoothManager.h"
#import "AVaudioplayerManager.h"
#import "DataManager.h"

#define SAMPLE_RATE 1411200  //22050 //44100 //88200 //352800 //705600 //1411200 //2000000
#define FRAMESIZE  512
#define NUMCHANNELS 2
#define kOutputBus 0
#define kInputBus 1

/// Nyquist Maximum Frequency
const Float32 NyquistMaxFreq = SAMPLE_RATE/2.0;
/// caculates HZ value for specified index from a FFT bins vector
Float32 frequencyHerzValue(long frequencyIndex, long fftVectorSize, Float32 nyquistFrequency ) {
    return ((Float32)frequencyIndex/(Float32)fftVectorSize) * nyquistFrequency;
}
// The Main FFT Helper
FFTHelperRef *fftConverter = NULL;
//Accumulator Buffer=====================
#pragma mark - 这个地方能改破音
const UInt32 accumulatorDataLenght = 16384;  //16384; //32768; 65536; 131072;
UInt32 accumulatorFillIndex = 0;
Float32 *dataAccumulator = nil;
static void initializeAccumulator() {
    dataAccumulator = (Float32*) malloc(sizeof(Float32)*accumulatorDataLenght);
    accumulatorFillIndex = 0;
}
static void destroyAccumulator() {
    if (dataAccumulator!=NULL) {
        free(dataAccumulator);
        dataAccumulator = NULL;
    }
    accumulatorFillIndex = 0;
}
static BOOL accumulateFrames(Float32 *frames, UInt32 lenght) { //returned YES if full, NO otherwise.
    //        float zero = 0.0;
    //        vDSP_vsmul(frames, 1, &zero, frames, 1, lenght);
    
    if (accumulatorFillIndex>=accumulatorDataLenght) { return YES; } else {
        memmove(dataAccumulator+accumulatorFillIndex, frames, sizeof(Float32)*lenght);
        accumulatorFillIndex = accumulatorFillIndex+lenght;
        if (accumulatorFillIndex>=accumulatorDataLenght) { return YES; }
    }
    return NO;
}
static void emptyAccumulator() {
    accumulatorFillIndex = 0;
    memset(dataAccumulator, 0, sizeof(Float32)*accumulatorDataLenght);
}
//=======================================
//==========================Window Buffer
const UInt32 windowLength = accumulatorDataLenght;
Float32 *windowBuffer= NULL;
//=======================================
/// max value from vector with value index (using Accelerate Framework)
static Float32 vectorMaxValueACC32_index(Float32 *vector, unsigned long size, long step, unsigned long *outIndex) {
    Float32 maxVal;
    vDSP_maxvi(vector, step, &maxVal, outIndex, size);
    return maxVal;
}
int count = 0;
NSMutableArray *dataArray = [NSMutableArray array];
dispatch_queue_t dataComputeQueue = dispatch_queue_create("DataComputeQueue", DISPATCH_QUEUE_SERIAL);
NSString *color = @"";
DataManager *manager = [[DataManager alloc]init];
///returns HZ of the strongest frequency.
static Float32 strongestFrequencyHZ(Float32 *buffer, FFTHelperRef *fftHelper, UInt32 frameSize, Float32 *freqValue) {
    
    
    //the actual FFT happens here
    //****************************************************************************
    Float32 *fftData = computeFFT(fftHelper, buffer, frameSize);
    //****************************************************************************
    
    fftData[0] = 0.0;
    unsigned long length = frameSize/2.0;
    Float32 max = 0;
    unsigned long maxIndex = 0;
    max = vectorMaxValueACC32_index(fftData, length, 1, &maxIndex);
    if (freqValue!=NULL) { *freqValue = max; }
    Float32 HZ = frequencyHerzValue(maxIndex, length, NyquistMaxFreq);
    //    __block Float32 copy_max = max;
    //    Float32 copy_max = max;
    //    dispatch_async(comQueue, ^{
    max = max*1000000;
    //    QCLog(@"%f",max);
    //        NSNumber *FFTData = [NSNumber numberWithFloat:copy_max];
    //        [[NSNotificationCenter defaultCenter] postNotificationName:@"FFTNotification" object:FFTData];
    if (count==3) {
        
        //        NSLog(@"------%@",dataArray);
        //        dispatch_sync(dataComputeQueue, ^{
        NSNumber *min = dataArray[0];
        int minNumber = 0;
        for (int i = 1; i < 3; i++) {
            if ([min floatValue] < [dataArray[i] floatValue]) {
                min = dataArray[i];
                minNumber = i;
            }
        }
        dataArray[minNumber] = [NSNumber numberWithFloat:0.0];
        color = [NSString stringWithFormat:@"%02x%02x%02x",[dataArray[0] intValue],[dataArray[1] intValue],[dataArray[2] intValue]];
        
        BOOL isRhythm = [[NSUserDefaults standardUserDefaults] boolForKey:kRhythmMode];
        BOOL isRecord = [[NSUserDefaults standardUserDefaults] boolForKey:kStartRecord];
        
        if (([[AVaudioplayerManager standardManager].player isPlaying] && isRhythm) || isRecord) {
            color = [color substringToIndex:6];
//            NSLog(@"--------%@",color);
            NSString *data = [NSString stringWithFormat:@"01%@",color];
            [[BluetoothManager standardManager] writCommad:data];
        }
        //        });
        count = 0;
        color = @"";
        [dataArray removeAllObjects];
    }else{
        [dataArray addObject:[NSNumber numberWithFloat:max]];
        count++;
    }
    return HZ;
}
__weak UILabel *labelToUpdate = nil;
#pragma mark MAIN CALLBACK
void AudioCallback( Float32 * buffer, UInt32 frameSize, void * userData )
{
    //take only data from 1 channel
    //        Float32 zero = 0.0;
    //        vDSP_vsadd(buffer, 1, &zero, buffer, 1, frameSize*NUMCHANNELS);
    
    
    
    if (accumulateFrames(buffer, frameSize)==YES) { //if full
        
        //windowing the time domain data before FFT (using Blackman Window)
        if (windowBuffer==NULL) { windowBuffer = (Float32*) malloc(sizeof(Float32)*windowLength); }
        vDSP_blkman_window(windowBuffer, windowLength, 0);
        vDSP_vmul(dataAccumulator, 1, windowBuffer, 1, dataAccumulator, 1, accumulatorDataLenght);
        //=========================================
        
        
        Float32 maxHZValue = 0;
        Float32 maxHZ = strongestFrequencyHZ(dataAccumulator, fftConverter, accumulatorDataLenght, &maxHZValue);
        while (maxHZ>255) {
            maxHZ -= 255;
        }
        emptyAccumulator(); //empty the accumulator when finished
    }
    memset(buffer, 0, sizeof(Float32)*frameSize*NUMCHANNELS);
}
@interface RGBManager()<AVAudioPlayerDelegate>
@property (nonatomic, strong) AVAudioPlayer *player;
@end
@implementation RGBManager
+ (instancetype)standardManager
{
    static RGBManager *m = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        m = [[RGBManager alloc]init];
    });
    return m;
}
- (instancetype)init
{
    self = [super init];
    if (self) {
        //initialize stuff
#warning mark - 后台传输旋律的方法
        fftConverter = FFTHelperCreate(accumulatorDataLenght);
        initializeAccumulator();
        [self initMomuAudio];
    }
    return self;
}
- (void)doWork
{
}
-(void) initMomuAudio {
    bool result = false;
    result = MoAudio::init( SAMPLE_RATE, FRAMESIZE, NUMCHANNELS, false);
    result = MoAudio::start(AudioCallback, NULL );
}
-(void) dealloc {
    destroyAccumulator();
    FFTHelperRelease(fftConverter);
}

+ (void)stop
{
    MoAudio::stop();
}

+ (void)start
{
    MoAudio::start(AudioCallback, NULL );
}


@end
